#include "platform.h"
#include "event.h"

    /**
     *  Constructor
     */
UDKEvent::UDKEvent(bool bManualReset,bool bInitialState){
	pthread_cond_init(&CVariable, 0);
	pthread_mutex_init(&Mutex, 0);
	
	m_bState = false;
	m_bAutoReset = !bManualReset;
	
	if(bInitialState) SetEvent();
}

    /**
     *  Destructor
     */
UDKEvent::~UDKEvent(){
	DestroyEvent();	
}

int UDKEvent::WaitForEvent(uint64_t milliseconds){
	int tempResult;
	if(milliseconds == 0){
		tempResult = pthread_mutex_trylock(&Mutex);
		if(tempResult == EBUSY){
			return kWaitTimeout;
		}
	}else{
		tempResult = pthread_mutex_lock(&Mutex);
	}


	int result = UnlockedWaitForEvent(milliseconds);

	tempResult = pthread_mutex_unlock(&Mutex);

	return result;
}


int UDKEvent::UnlockedWaitForEvent(uint64_t milliseconds){
	int result = 0;
	if(!m_bState){
		//Zero-timeout event state check optimization
		if(milliseconds == 0){
			return kWaitTimeout;
		}

		timespec ts;
		if(milliseconds != (uint64_t) -1){
			timeval tv;
			gettimeofday(&tv, NULL);

			uint64_t nanoseconds = ((uint64_t) tv.tv_sec) * 1000 * 1000 * 1000 + milliseconds * 1000 * 1000 + ((uint64_t) tv.tv_usec) * 1000;

			ts.tv_sec = nanoseconds / 1000 / 1000 / 1000;
			ts.tv_nsec = (nanoseconds - ((uint64_t) ts.tv_sec) * 1000 * 1000 * 1000);
		}

		do
		{
			//Regardless of whether it's an auto-reset or manual-reset event:
			//wait to obtain the event, then lock anyone else out
			if(milliseconds != (uint64_t) -1){
				result = pthread_cond_timedwait(&CVariable, &Mutex, &ts);
			}else{
				result = pthread_cond_wait(&CVariable, &Mutex);
			}
		} while(result == 0 && !m_bState);

		if(result == 0 && m_bAutoReset){
			//We've only accquired the event if the wait succeeded
			m_bState = false;
		}
	}	else if(m_bAutoReset)	{
		//It's an auto-reset event that's currently available;
		//we need to stop anyone else from using it
		result = 0;
		m_bState = false;
	}
	//Else we're trying to obtain a manual reset event with a signaled state;
	//don't do anything
	result = (0==result)?kWaitSuccess:kWaitTimeout;
	return result;
}

int UDKEvent::DestroyEvent(){
	int result = pthread_cond_destroy(&CVariable);
	result = pthread_mutex_destroy(&Mutex);

	return 0;
}
int UDKEvent::SetEvent(){
	int result = pthread_mutex_lock(&Mutex);
	m_bState = true;
	//Depending on the event type, we either trigger everyone or only one
	if(true==m_bAutoReset){
		//event->State can be false if compiled with WFMO support
		if(m_bState)
		{
			result = pthread_mutex_unlock(&Mutex);		
			result = pthread_cond_signal(&CVariable);
			return 0;
		}
	}else{
		result = pthread_mutex_unlock(&Mutex);
		result = pthread_cond_broadcast(&CVariable);
	}
	return 0;
}

int UDKEvent::ResetEvent(){
	
	int result = pthread_mutex_lock(&Mutex);	
	m_bState = false;	
	result = pthread_mutex_unlock(&Mutex);
	return 0;
}

/*
int UDKEvent::PulseEvent(){
	SetEvent();
	ResetEvent();
	return 0;
}*/

